package ias.deepsearch.com.helper.xposed.module;

import android.os.IBinder;
import android.util.SparseArray;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * Created by root on 8/5/17.
 */

public class VMHelper {

    public static String getOwningPackage(Object windowState){
        try {
            Class clz = windowState.getClass();
            Method m = null;
            m = clz.getMethod("getOwningPackage");
            return (String) m.invoke(windowState);
        } catch (Exception e) {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(bo));
            return bo.toString();
        }
    }

    public static Object getAppWindowToken(Object windowState){
        try{
            Class clz = windowState.getClass();
            Field f =  clz.getDeclaredField("mAppToken");
            f.setAccessible(true);
            return  f.get(windowState);
        }catch(Throwable e){
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(bo));
            return bo.toString();
        }
    }

    public static Object getWindowToken(Object widnowState){
        try{
            Class clz = widnowState.getClass();
            Field f = clz.getDeclaredField("mToken");
            f.setAccessible(true);
            return  f.get(widnowState);
        }catch(Throwable e){
            e.printStackTrace();
            return null;
        }
    }


    public static Object reverseGet(Map map, Object val){
        Object ret = null;
        for (Object key:map.keySet())
            if (map.get(key).equals(val))
                return key;
        return null;
    }
    public static Map getWindowMap(Object wm){
        try {
            Field f = wm.getClass().getDeclaredField("mWindowMap");
            f.setAccessible(true);
            return (Map)f.get(wm);
        }catch(Exception e){
            e.printStackTrace();
            return null;
        }
    }
    public static Map getTokenMap(Object wm){
        try {
            Field f = wm.getClass().getDeclaredField("mTokenMap");
            f.setAccessible(true);
            return (Map)f.get(wm);
        }catch(Throwable e){
            e.printStackTrace();
            return null;
        }
    }


    public static String moveTaskToTop(Object wm, int i) {
        try{
            Class clz = wm.getClass();
            Method m = null;
            m = clz.getMethod("moveTaskToTop",Integer.TYPE);
            m.invoke(wm,i);
            return "success";
        }catch(Throwable e){
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(bo));
            return bo.toString();
        }
    }



    public static void setSendingToBottom(Object awtoken, boolean b) {
        try {
            Field f = awtoken.getClass().getClassLoader().
                    loadClass("com.android.server.wm.WindowToken").getDeclaredField("sendingToBottom");
            f.setAccessible(true);
            f.set(awtoken, b);
        }catch(Throwable e){
            e.printStackTrace();
        }
    }



    public static String toStringList(Object[] args) {
        if (args==null) return "null";
        StringBuilder sb = new StringBuilder();
        for (Object obj:args){
            if (obj==null)
                sb.append("null||||");
            else sb.append(obj.toString()).append("||||");
        }
        return sb.toString();
    }



    public static class WMS {
        public static String showCircularMask(Object wm, boolean b) {
            try {

                Method m = wm.getClass().getDeclaredMethod("showCircularMask",Boolean.TYPE);
                m.setAccessible(true);
                m.invoke(wm,b);
                return "success";
            }catch(Throwable e) {
                return dump(e);
            }
        }
        public static Object getFocursedWS(Object wm) {
            try {
                Field f = wm.getClass().getDeclaredField("mFocusedApp");
                f.setAccessible(true);
                Object appWindowToken = f.get(wm);
                Method m = appWindowToken.getClass().getDeclaredMethod("findMainWindow");
                m.setAccessible(true);
                return m.invoke(appWindowToken);
            }catch(Throwable e){
                e.printStackTrace();
            }
            return null;
        }
        public static void setmFocusedApp(Object wm, Object o) {
            try {
                Field f = wm.getClass().getDeclaredField("mFocusedApp");
                f.setAccessible(true);
                f.set(wm,o);
            }catch(Throwable e){
                e.printStackTrace();
            }
        }
        public static String moveTaskToBottom(Object wm, int i) {
            try{
                Class clz = wm.getClass();
                Method m = null;
                m = clz.getMethod("moveTaskToBottom",Integer.TYPE);
                m.invoke(wm,i);
                return "success";
            }catch(Throwable e){
                ByteArrayOutputStream bo = new ByteArrayOutputStream();
                e.printStackTrace(new PrintStream(bo));
                return bo.toString();
            }
        }
        public static String setAppVisiability(Object wm, Object arg,boolean visiable){
            try{
                Class clz = wm.getClass();
                Method m = null;
                m = clz.getMethod("setAppVisibility",IBinder.class,Boolean.TYPE);
                m.invoke(wm,arg,visiable);
                return "success";
            }catch(Throwable e){
                ByteArrayOutputStream bo = new ByteArrayOutputStream();
                e.printStackTrace(new PrintStream(bo));
                return bo.toString();
            }
        }

        public static SparseArray getTaskIDtoTask(Object wm) {
            try {
                Field f = wm.getClass().getDeclaredField("mTaskIdToTask");
                f.setAccessible(true);
                return (SparseArray)f.get(wm);
            }catch(Throwable e){
                e.printStackTrace();
                return null;
            }
        }
        public static String  performLayoutAndPlaceSurfacesLocked(Object wm){
            try{
                Class clz = wm.getClass();
                Method m =  clz.getDeclaredMethod("performLayoutAndPlaceSurfacesLocked");
                m.setAccessible(true);
                m.invoke(wm);
                m = clz.getDeclaredMethod("updateFocusedWindowLocked", Integer.TYPE,Boolean.TYPE);
                m.invoke(wm, 0 ,true);
                return "success";
            }catch(Throwable e){
                ByteArrayOutputStream bo = new ByteArrayOutputStream();
                e.printStackTrace(new PrintStream(bo));
                return bo.toString();
            }
        }
    }
    private static String dump(Throwable e) {
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        e.printStackTrace(new PrintStream(bo));
        return bo.toString();
    }
}
